from datetime import datetime, timedelta
from enum import Enum

from werkzeug.security import generate_password_hash, check_password_hash
from extensions import db


class UserRole(Enum):
    """用户角色枚举"""
    USER = "user"  # 普通用户
    PREMIUM = "premium"  # 高级用户
    VIP = "vip"  # VIP用户
    ADMIN = "admin"  # 管理员
    SUPER_ADMIN = "super_admin"  # 超级管理员

    @classmethod
    def get_role_permissions(cls, role):
        """获取角色权限"""
        permissions = {
            cls.USER: {
                'weekly_request_limit': 50,
                'models': ['gpt-4o-mini'],
                'can_view_stats': True,
                'can_manage_users': False,
                'can_view_all_requests': False,
                'can_modify_limits': False,
                'max_concurrent_requests': 1
            },
            cls.PREMIUM: {
                'weekly_request_limit': 500,
                'models': ['gpt-4o-mini', 'gpt-4o'],
                'can_view_stats': True,
                'can_manage_users': False,
                'can_view_all_requests': False,
                'can_modify_limits': False,
                'max_concurrent_requests': 3
            },
            cls.VIP: {
                'weekly_request_limit': 2000,
                'models': ['gpt-4o-mini', 'gpt-4o', 'claude-3-5-sonnet-20241022'],
                'can_view_stats': True,
                'can_manage_users': False,
                'can_view_all_requests': False,
                'can_modify_limits': False,
                'max_concurrent_requests': 5
            },
            cls.ADMIN: {
                'weekly_request_limit': 10000,
                'models': ['gpt-4o-mini', 'gpt-4o', 'claude-3-5-sonnet-20241022'],
                'can_view_stats': True,
                'can_manage_users': True,
                'can_view_all_requests': True,
                'can_modify_limits': True,
                'max_concurrent_requests': 10
            },
            cls.SUPER_ADMIN: {
                'weekly_request_limit': -1,  # 无限制
                'models': ['all'],
                'can_view_stats': True,
                'can_manage_users': True,
                'can_view_all_requests': True,
                'can_modify_limits': True,
                'max_concurrent_requests': -1  # 无限制
            }
        }
        return permissions.get(role, permissions[cls.USER])


class User(db.Model):
    """用户模型"""
    __tablename__ = 'users'

    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(80), unique=True, nullable=False, index=True)
    email = db.Column(db.String(120), unique=True, nullable=False, index=True)
    password_hash = db.Column(db.String(255), nullable=False)
    role = db.Column(db.Enum(UserRole), default=UserRole.USER, nullable=False)

    # 账户信息
    balance = db.Column(db.Float, default=0.0, nullable=False)  # 账户余额
    weekly_request_limit = db.Column(db.Integer, default=50, nullable=False)  # 每周请求限制

    # 时间戳
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    last_login = db.Column(db.DateTime)

    # 状态
    is_active = db.Column(db.Boolean, default=True, nullable=False)
    is_verified = db.Column(db.Boolean, default=False, nullable=False)

    # 关联关系
    requests = db.relationship('RequestRecord', backref='user', lazy='dynamic', cascade='all, delete-orphan')
    cost_records = db.relationship('CostRecord', backref='user', lazy='dynamic', cascade='all, delete-orphan')
    payment_records = db.relationship('PaymentRecord', backref='user', lazy='dynamic', cascade='all, delete-orphan')

    def set_password(self, password):
        """设置密码"""
        self.password_hash = generate_password_hash(password)

    def check_password(self, password):
        """验证密码"""
        return check_password_hash(self.password_hash, password)

    def get_weekly_request_count(self):
        """获取本周请求次数"""
        # 计算本周开始时间（周一00:00:00）
        now = datetime.utcnow()
        days_since_monday = now.weekday()
        # 正确计算本周一的开始时间
        week_start = now.replace(hour=0, minute=0, second=0, microsecond=0) - timedelta(days=days_since_monday)

        return self.requests.filter(
            RequestRecord.created_at >= week_start,
            RequestRecord.status == 'completed'
        ).count()

    def can_make_request(self):
        """检查是否可以发起请求"""
        if not self.is_active:
            return False, "账户已被禁用"

        weekly_count = self.get_weekly_request_count()
        if weekly_count >= self.weekly_request_limit:
            return False, f"已达到每周请求限制({self.weekly_request_limit}次)"

        return True, "可以发起请求"

    def get_total_cost(self):
        """获取总消费"""
        return db.session.query(db.func.sum(CostRecord.cost)).filter(
            CostRecord.user_id == self.id
        ).scalar() or 0.0

    def get_permissions(self):
        """获取用户权限"""
        return UserRole.get_role_permissions(self.role)

    def has_permission(self, permission):
        """检查用户是否有特定权限"""
        permissions = self.get_permissions()
        return permissions.get(permission, False)

    def can_access_model(self, model_name):
        """检查用户是否可以访问特定模型"""
        permissions = self.get_permissions()
        allowed_models = permissions.get('models', [])
        return 'all' in allowed_models or model_name in allowed_models

    def get_effective_weekly_limit(self):
        """获取有效的每周请求限制"""
        permissions = self.get_permissions()
        role_limit = permissions.get('weekly_request_limit', 100)
        if role_limit == -1:  # 无限制
            return float('inf')
        # 返回角色限制和用户自定义限制的较小值
        return min(role_limit, self.weekly_request_limit)

    def can_make_request_with_model(self, model_name):
        """检查用户是否可以使用特定模型发起请求"""
        return self.can_make_request() and self.can_access_model(model_name)

    def is_admin(self):
        """检查用户是否是管理员"""
        return self.role in [UserRole.ADMIN, UserRole.SUPER_ADMIN]

    def is_super_admin(self):
        """检查用户是否是超级管理员"""
        return self.role == UserRole.SUPER_ADMIN

    def to_dict(self):
        """转换为字典"""
        permissions = self.get_permissions()
        return {
            'id': self.id,
            'username': self.username,
            'email': self.email,
            'role': self.role.value,
            'balance': self.balance,
            'weekly_request_limit': self.weekly_request_limit,
            'effective_weekly_limit': self.get_effective_weekly_limit(),
            'weekly_request_count': self.get_weekly_request_count(),
            'total_cost': self.get_total_cost(),
            'created_at': self.created_at.isoformat(),
            'last_login': self.last_login.isoformat() if self.last_login else None,
            'is_active': self.is_active,
            'is_verified': self.is_verified,
            'permissions': permissions
        }


class RequestRecord(db.Model):
    """请求记录模型"""
    __tablename__ = 'request_records'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
    session_id = db.Column(db.String(36), nullable=False, index=True)

    # 请求信息
    query = db.Column(db.Text, nullable=False)
    model = db.Column(db.String(100), nullable=False)
    status = db.Column(db.String(20), default='pending', nullable=False)  # pending, processing, completed, failed

    # Token统计
    input_tokens = db.Column(db.Integer, default=0)
    output_tokens = db.Column(db.Integer, default=0)
    total_tokens = db.Column(db.Integer, default=0)

    # 响应信息
    response = db.Column(db.Text)
    error_message = db.Column(db.Text)

    # 时间统计
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    started_at = db.Column(db.DateTime)
    completed_at = db.Column(db.DateTime)
    duration = db.Column(db.Float)  # 执行时长（秒）

    # 关联关系
    cost_record = db.relationship('CostRecord', backref='request', uselist=False, cascade='all, delete-orphan')

    def calculate_duration(self):
        """计算执行时长"""
        if self.started_at and self.completed_at:
            self.duration = (self.completed_at - self.started_at).total_seconds()

    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'session_id': self.session_id,
            'query': self.query,
            'model': self.model,
            'status': self.status,
            'input_tokens': self.input_tokens,
            'output_tokens': self.output_tokens,
            'total_tokens': self.total_tokens,
            'duration': self.duration,
            'created_at': self.created_at.isoformat(),
            'completed_at': self.completed_at.isoformat() if self.completed_at else None,
            'cost': self.cost_record.cost if self.cost_record else 0.0
        }


class CostRecord(db.Model):
    """费用记录模型"""
    __tablename__ = 'cost_records'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
    request_id = db.Column(db.Integer, db.ForeignKey('request_records.id'), nullable=False, unique=True)

    # 费用信息
    model = db.Column(db.String(100), nullable=False)
    input_tokens = db.Column(db.Integer, nullable=False)
    output_tokens = db.Column(db.Integer, nullable=False)
    input_cost = db.Column(db.Float, nullable=False)  # 输入token费用
    output_cost = db.Column(db.Float, nullable=False)  # 输出token费用
    cost = db.Column(db.Float, nullable=False)  # 总费用

    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)

    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'request_id': self.request_id,
            'model': self.model,
            'input_tokens': self.input_tokens,
            'output_tokens': self.output_tokens,
            'input_cost': self.input_cost,
            'output_cost': self.output_cost,
            'cost': self.cost,
            'created_at': self.created_at.isoformat()
        }


class PaymentRecord(db.Model):
    """支付记录模型"""
    __tablename__ = 'payment_records'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)

    # 支付信息
    amount = db.Column(db.Float, nullable=False)  # 充值金额
    payment_method = db.Column(db.String(50), nullable=False)  # 支付方式
    transaction_id = db.Column(db.String(100), unique=True)  # 交易ID
    status = db.Column(db.String(20), default='pending', nullable=False)  # pending, completed, failed, refunded

    # 时间戳
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    completed_at = db.Column(db.DateTime)

    # 备注
    note = db.Column(db.Text)

    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'amount': self.amount,
            'payment_method': self.payment_method,
            'transaction_id': self.transaction_id,
            'status': self.status,
            'created_at': self.created_at.isoformat(),
            'completed_at': self.completed_at.isoformat() if self.completed_at else None,
            'note': self.note
        }


class ModelPricing(db.Model):
    """模型定价模型"""
    __tablename__ = 'model_pricing'

    id = db.Column(db.Integer, primary_key=True)
    model_name = db.Column(db.String(100), unique=True, nullable=False, index=True)
    platform = db.Column(db.String(50), nullable=False)  # openai, anthropic等

    # 定价信息（每1000个token的价格，单位：美元）
    input_price_per_1k = db.Column(db.Float, nullable=False)
    output_price_per_1k = db.Column(db.Float, nullable=False)

    # 状态
    is_active = db.Column(db.Boolean, default=True, nullable=False)

    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)

    @classmethod
    def calculate_cost(cls, model_name, input_tokens, output_tokens):
        """计算费用"""
        pricing = cls.query.filter_by(model_name=model_name, is_active=True).first()
        if not pricing:
            # 如果没有找到定价信息，使用默认价格
            input_cost = (input_tokens / 1000) * 0.01  # 默认$0.01/1k tokens
            output_cost = (output_tokens / 1000) * 0.03  # 默认$0.03/1k tokens
        else:
            input_cost = (input_tokens / 1000) * pricing.input_price_per_1k
            output_cost = (output_tokens / 1000) * pricing.output_price_per_1k

        return input_cost, output_cost, input_cost + output_cost

    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'model_name': self.model_name,
            'platform': self.platform,
            'input_price_per_1k': self.input_price_per_1k,
            'output_price_per_1k': self.output_price_per_1k,
            'is_active': self.is_active
        }


# 为了向后兼容，创建QueryRecord作为RequestRecord的别名
class UserStats(db.Model):
    """用户行为统计模型"""
    __tablename__ = 'user_stats'

    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, unique=True, index=True)
    
    # 问答统计
    total_queries = db.Column(db.Integer, default=0, nullable=False)  # 总问答次数
    successful_queries = db.Column(db.Integer, default=0, nullable=False)  # 成功问答次数
    failed_queries = db.Column(db.Integer, default=0, nullable=False)  # 失败问答次数
    
    # 模型使用统计
    model_usage = db.Column(db.JSON, default=dict, nullable=False)  # 各模型使用次数 {"gpt-4o": 10, "claude": 5}
    
    # Token统计
    total_input_tokens = db.Column(db.BigInteger, default=0, nullable=False)  # 总输入token
    total_output_tokens = db.Column(db.BigInteger, default=0, nullable=False)  # 总输出token
    total_tokens = db.Column(db.BigInteger, default=0, nullable=False)  # 总token数
    
    # 费用统计
    total_cost = db.Column(db.Float, default=0.0, nullable=False)  # 总费用
    
    # 时间统计
    total_duration = db.Column(db.Float, default=0.0, nullable=False)  # 总执行时长（秒）
    avg_duration = db.Column(db.Float, default=0.0, nullable=False)  # 平均执行时长（秒）
    
    # 最后活动时间
    last_query_at = db.Column(db.DateTime)  # 最后一次查询时间
    
    # 时间戳
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    
    # 关联关系
    user = db.relationship('User', backref=db.backref('stats', uselist=False, cascade='all, delete-orphan'))
    
    def update_query_stats(self, request_record):
        """更新查询统计"""
        self.total_queries += 1
        if request_record.status == 'completed':
            self.successful_queries += 1
        else:
            self.failed_queries += 1
            
        # 更新模型使用统计
        if not self.model_usage:
            self.model_usage = {}
        model_count = self.model_usage.get(request_record.model, 0)
        self.model_usage[request_record.model] = model_count + 1
        
        # 更新token统计
        self.total_input_tokens += request_record.input_tokens or 0
        self.total_output_tokens += request_record.output_tokens or 0
        self.total_tokens += request_record.total_tokens or 0
        
        # 更新时间统计
        if request_record.duration:
            self.total_duration += request_record.duration
            self.avg_duration = self.total_duration / self.total_queries
            
        # 更新费用统计
        if request_record.cost_record:
            self.total_cost += request_record.cost_record.cost
            
        # 更新最后活动时间
        self.last_query_at = request_record.completed_at or datetime.utcnow()
        self.updated_at = datetime.utcnow()
    
    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'user_id': self.user_id,
            'total_queries': self.total_queries,
            'successful_queries': self.successful_queries,
            'failed_queries': self.failed_queries,
            'model_usage': self.model_usage,
            'total_input_tokens': self.total_input_tokens,
            'total_output_tokens': self.total_output_tokens,
            'total_tokens': self.total_tokens,
            'total_cost': self.total_cost,
            'total_duration': self.total_duration,
            'avg_duration': self.avg_duration,
            'last_query_at': self.last_query_at.isoformat() if self.last_query_at else None,
            'created_at': self.created_at.isoformat(),
            'updated_at': self.updated_at.isoformat()
        }


class ConversationSession(db.Model):
    """对话会话模型"""
    __tablename__ = 'conversation_sessions'
    
    id = db.Column(db.Integer, primary_key=True)
    user_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False, index=True)
    session_id = db.Column(db.String(36), nullable=False, index=True)
    
    # 添加复合唯一约束：同一用户的 session_id 唯一
    __table_args__ = (db.UniqueConstraint('user_id', 'session_id', name='uq_user_session'),)
    
    # 会话信息
    title = db.Column(db.String(200))  # 会话标题（可从第一个查询生成）
    conversation_dir = db.Column(db.String(255), nullable=False)  # 对话目录路径
    timestamp_folder = db.Column(db.String(50), nullable=False)  # 时间戳文件夹名
    
    # 对话统计
    message_count = db.Column(db.Integer, default=0, nullable=False)  # 消息数量
    total_tokens = db.Column(db.Integer, default=0, nullable=False)  # 总token数
    total_cost = db.Column(db.Float, default=0.0, nullable=False)  # 总费用
    
    # 文件相关
    conversation_file = db.Column(db.String(255))  # 对话文件路径
    metadata_file = db.Column(db.String(255))  # 元数据文件路径
    execution_files = db.Column(db.JSON, default=list, nullable=False)  # 执行过程文件列表
    download_files = db.Column(db.JSON, default=list, nullable=False)  # 下载文件记录列表
    total_size = db.Column(db.BigInteger, default=0, nullable=False)  # 总文件大小（字节）
    
    # 时间戳
    created_at = db.Column(db.DateTime, default=datetime.utcnow, nullable=False)
    updated_at = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
    last_message_at = db.Column(db.DateTime)  # 最后一条消息时间
    
    # 关联关系
    user = db.relationship('User', backref='conversation_sessions')
    requests = db.relationship('RequestRecord', backref='conversation_session', 
                             primaryjoin='ConversationSession.session_id == RequestRecord.session_id',
                             foreign_keys='RequestRecord.session_id')
    
    def update_stats(self, request_record):
        """更新会话统计信息"""
        self.message_count += 1
        self.total_tokens += request_record.total_tokens or 0
        if request_record.cost_record:
            self.total_cost += request_record.cost_record.cost
        self.last_message_at = datetime.utcnow()
        self.updated_at = datetime.utcnow()
        
        # 如果没有标题，从第一个查询生成
        if not self.title and request_record.query:
            self.title = request_record.query[:50] + ('...' if len(request_record.query) > 50 else '')
    
    def to_dict(self):
        """转换为字典"""
        return {
            'id': self.id,
            'user_id': self.user_id,
            'session_id': self.session_id,
            'title': self.title,
            'conversation_dir': self.conversation_dir,
            'timestamp_folder': self.timestamp_folder,
            'message_count': self.message_count,
            'total_tokens': self.total_tokens,
            'total_cost': self.total_cost,
            'conversation_file': self.conversation_file,
            'metadata_file': self.metadata_file,
            'total_size': self.total_size,
            'created_at': self.created_at.isoformat(),
            'updated_at': self.updated_at.isoformat(),
            'last_message_at': self.last_message_at.isoformat() if self.last_message_at else None
        }


# 保持向后兼容
ConversationFile = ConversationSession  # 重定向到新的模型


QueryRecord = RequestRecord
